#include <unistd.h>
#include <sys/socket.h>
#include <string.h> // memset()、bzero()
#include <netinet/tcp.h>
// #include <sys/types.h>
// #include <sys/socket.h>

#include "./Socket.h"
#include "./InetAddress.h"
#include "../utility/Logger.h"

Socket::Socket(int sockFd) : sockFd_(sockFd)
{
}

Socket::~Socket()
{
    ::close(this->sockFd_);
}

int Socket::getFd() const
{
    return this->sockFd_;
}

void Socket::bindAddr(const InetAddress &localAddr)
{
    // TODO: (sockaddr *) -> C++方式的类型转换
    if (::bind(this->sockFd_, (sockaddr *)localAddr.getAddr(), sizeof(sockaddr_in)) != 0)
    {
        LOG_FATAL("bind sockfd:%d fail\n", this->sockFd_);
    }
}

void Socket::listen()
{
    if (::listen(this->sockFd_, 1024) != 0)
    {
        LOG_FATAL("listen sockfd:%d fail\n", this->sockFd_);
    }
}

int Socket::accept(InetAddress *peerAddr)
{
    sockaddr_in addr{};
    socklen_t len = sizeof(addr);
    ::bzero(&addr, len);

    // accept4()增强，可以直接设置非阻塞等标志
    // int connfd = ::accept(this->sockFd_, (sockaddr *)&addr, &len);
    int connfd = ::accept4(this->sockFd_, (sockaddr *)&addr, &len, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (connfd >= 0)
    {
        peerAddr->setAddr(addr);
    }
    return connfd;
}

void Socket::shutdownWrite()
{
    if (::shutdown(this->sockFd_, SHUT_WR) < 0)
    {
        LOG_ERROR("shutdownWrite error");
    }
}

void Socket::setTcpNoDelay(bool on)
{
    int opt = on ? 1 : 0;
    ::setsockopt(this->sockFd_, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
}

void Socket::setReuseAddr(bool on)
{
    int opt = on ? 1 : 0;
    ::setsockopt(this->sockFd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
}

void Socket::setReusePort(bool on)
{
    int opt = on ? 1 : 0;
    ::setsockopt(this->sockFd_, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
}

void Socket::setKeepAlive(bool on)
{
    int opt = on ? 1 : 0;
    ::setsockopt(this->sockFd_, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
}